<template>
	<view style="height: 160vh; background: #181818; position: relative; color: #ffffff;">
		
		<!--模态框是否确认删除设备-->
		<u-modal :showCancelButton='true' @confirm='modalConfirm' @cancel='modalCancel' :show="showModal"
			cancelColor='#FFFFFF' confirmColor='#FFFFFF' title="查询附近的设备需要您授权蓝牙权限"></u-modal>
		
		<bakc text="选择设备" :isReturn="false" textMLeft='margin-left: 130rpx;' />

		<!--设备列表 判断  equipmentList数组的长度是否为空 为空则没有设备则不显示-->
		<view style="height: 30rpx;"></view>
		<view class="equipment" v-if="equipmentList.length">
			<view v-for="item in equipmentList" @click="distributionNetworkOrQueyrEquipmentData(item)">
				<!--判断是否是已配网但是离线的设备但是又开启了蓝牙需要重新配网-->
				<view class="item" v-if="isNetworkDisconnect(item.status,item.mac)">
					<image class="backdrop" src="../../static/mecha/select_equipment/equipment.png"
						style="width: 330rpx; height:310rpx ;" />
					<image class="equipment" :src="item.appearance.appearanceImg"
						style="width: 330rpx; height:220rpx ;" />

					<view class="text" v-if="bindDevice.get(item.mac)">{{ bindDevice.get(item.mac) }}</view>
					<view class="text" v-else>{{ item.deviceName ? item.deviceName : '环境哨兵甲醛在线检测仪'  }}</view>


					<!--设备在线状态-->
					<view class="status" v-if="item.status ==  equipmentSatus.newEquipment">
						<view style="display: flex;">
							<view style="width: 10rpx;"></view>
							<text class="online" v-if="bindDevice.get(item.mac)">配网</text>
							<text class="online" v-else>NEW</text>
						</view>
					</view>
					<view class="status" v-else>
						<view style="display: flex;">
							<text v-if="item.status ==  equipmentSatus.online" class="online">在线</text>
							<text v-if="item.status ==  equipmentSatus.offline" class="online">离线</text>
						</view>
					</view>
				</view>
			</view>

		</view>

		<!--暂无设备显示 -->
		<view class="no_equipment" v-else>
			<image class="backdrop"
				src="https://yaolupail.obs.cn-east-3.myhuaweicloud.com:443/hjsbjj/none.png?AccessKeyId=LYTX473LFFD5QZN2ZLAR&Expires=1728526721&Signature=WtaSyjM04MqXS5gOhgKDgQOD00A%3D"
				style="width: 280rpx; height:430rpx ;" />
			<view style="height: 70rpx;"></view>
			<view>请把手机尽量靠近设备</view>
		</view>
	</view>
</template>

<script>
	import {
		searchEq,
		searchEqByQuery
	} from '@/config/api.js';
	var mqtt = require('utils/mqtt.js');
	const host = 'wxs://www.yaoluyiqi.com:8084/mqtt';
	export default {
		data() {
			return {
				
				//蓝牙权限弹窗
				showModal: false,
				
				isLoaderPage: true,
				//mqtt client
				client: {},
				//搜索设备名称的前缀
				equipmentPrefix: "JQ1",
				//搜索到的蓝牙设备用maq集合进行去重
				equipmentMap: new Map(),

				//绑定集合map集合
				bindDevice: new Map(),

				//从数据库里面查询出的设备集合
				devices: [],

				//设备集合
				equipmentList: [],
				//设备状态对象
				equipmentSatus: {
					offline: 1, //离线,
					online: 2, //在线
					newEquipment: 3 //新设备
				},
				//蓝牙超时时间
				bluetoothTimeOut: 3000, //1秒
			}
		},
		onLoad() {
			uni.hideTabBar();
			//vue bus 事件总线加载 detection 页面数据
			this.$bus.$on('refresh_new_page', (mac) => {
				this.refreshList();
			});

			//初始化代码
			this.initDeviceList();
			this.connectMqtt();
			
			//心态超时
			this.heartbeatMonitoring(); 

		},
		onPullDownRefresh() {
			let _this = this
			setTimeout(function() {
				_this.refreshStatus();
				uni.stopPullDownRefresh();
			}, 1500);
		},
		methods: {
			
			//权限弹窗层确认取消
			modalConfirm(){
				this.showModal = false;
				uni.showLoading({
					title: '获取权限中.....',
					mask: true
				})
				setTimeout(()=>{
					uni.hideLoading();
					this.initBluetooth();
				},5000)
			},
			
			modalCancel(){
				this.showModal = false;
			},
			
		    //把心跳超时的设备全部 改成离线
			heartbeatMonitoring(){
				
				setInterval(()=>{
					if(this.vuex_select_equipment.timestamp){
						 //判断选中的设备是否已经离线
						 var now = new Date().getTime();
						 //最近的时间戳
						 var timestamp = this.vuex_select_equipment.timestamp + 9000;
						 if(timestamp < now){
							//设备离线
							let selectEquipmen = this.vuex_select_equipment;
							this.$set(selectEquipmen, 'status', this.equipmentSatus.offline);
							
							
							//新连接设备也赋值
							
							let newEquipment = this.vuex_new_equipment;
							this.$set(newEquipment, 'status', this.equipmentSatus.offline);
							
						 }
					}
				},1000)
				
			},

			//判断用户近期使用的设备 并直接跳转
			recentUse() {
				let timeMax = 0;
				let mac;
				//获取到最近使用的设备
				for (let item of this.vuex_recent_equipment) {
					let arr = item.split(":");
					let time = arr[1] - 0;
					if (timeMax < time) {
						timeMax = time;
						mac = arr[0];
					}
				}

				//2循环遍历找到该设备 
				for (let item of this.equipmentList) {
					if (item.mac == mac) {
						this.distributionNetworkOrQueyrEquipmentData(item);
					}
				}

			},

			//判断设备是否是已经配网 但是已断开网络 开起了蓝牙
			isNetworkDisconnect(status, mac) {
				if (this.equipmentSatus.offline == status && this.bindDevice.get(mac) && this.equipmentMap.get(mac)) {
					return false;
				}
				return true;
			},

			//刷新列表
			refreshList() {
				//初始化
				this.equipmentList = [];
				this.equipmentMap = new Map();
				this.bindDevice = new Map();
				this.initDeviceList();
			},

			//初始化设备列表
			async initDeviceList() {
				await this.initBluetooth();
				await this.boundDevice();
				//蓝牙时间戳刷新设备是否存在
				this.timestampJudgment();

			},

			//设备排序方法 
			sortDeviceList() {
				this.equipmentList.sort(function(a, b) {
					return b.status - a.status;
				});
			},


			//刷新设备
			refreshStatus() {
				this.equipmentMap = new Map();
				this.equipmentList = [];
				this.boundDevice();
			},


			//蓝牙设备时间戳判断，如果equipmentMap 的value 时间戳 + bluetoothTimeOut < 当前时间戳 说明设备断连
			// _this.equipmentMap.set(mac, Date().now())
			timestampJudgment() {
				setInterval(async () => {
					for (let item of this.equipmentMap) {
						//遍历出this.equipmentMap 结构是这样的 ["C04E30A50E12", 1696659340890]
						let mac = item[0];
						let timestamp = item[1];
						//判断时间戳是否过期
						if (timestamp + this.bluetoothTimeOut < Date.now()) {
							//说明该设备已经离线断开 对存储设备的 数组和 map 进行删除
							//1 对map进行删除
							this.equipmentMap.delete(mac);

							//2删除绑定设备map
							this.bindDevice.delete(mac);

							//3 删除数组
							this.deleteEquipmentListByMac(mac);

							// 重新将查询出的设备信息分组到map中
							this.devicesGroup();

						}
					}
				}, 1300)

			},


			//通过mac 地址删除equipmentList的元素
			deleteEquipmentListByMac(mac) {
				//通过mac 地址找寻到这个设备
				for (var i = 0; i < this.equipmentList.length; i++) {
					if (this.equipmentList[i].mac == mac) {
						this.equipmentList.splice(i, 1);
						return;
					}
				}
			},


			//根据类型判断是去给设备配网还是去查询设备数据
			distributionNetworkOrQueyrEquipmentData(item) {
				this.$u.vuex('vuex_select_mac', '')
				this.$u.vuex('vuex_select_equipment', {});
				//把用户选择的设备存储到vuex中供给全部组件使用
				this.$u.vuex('vuex_select_mac', item.mac)
				this.$u.vuex('vuex_select_equipment', item);
				//判断该设备是否为蓝牙搜索出来的新设备
				if (item.status == this.equipmentSatus.newEquipment) {
					//跳转到配对页面
					this.routeJump("pages/connectionNetwork/connectionNetwork");
				} else {
					this.saveUseTime(item);
					//跳转到首页
					this.routeJump("pages/detection/detection");
				}
			},

			//保存用户最近使用的设备
			saveUseTime(item) {
				//保存改该设备的一个使用时间
				let evenNumbers = this.vuex_recent_equipment.filter(data => {
					let isReturn = data.indexOf(item.mac) > -1;
					return !isReturn;
				});
				evenNumbers.push(item.mac + ":" + new Date().getTime());
				this.$u.vuex('vuex_recent_equipment', evenNumbers);
			},

			//路由跳转
			routeJump(path) {
				if (path.indexOf("detection") > -1) {
					uni.showLoading({
						title: '加载中...',
						mask: true
					})
					//让detection 页面进行数据加载
					this.$bus.$emit('loader_detection');
					uni.switchTab({
						url: '/pages/detection/detection',
						fail: (e) => {}
					});
				} else {
					uni.$u.route({
						type: 'redirect',
						url: path
					})
				}
			},

			//查询我已经绑定的设备
			async boundDevice() {
				//生成请求数据
				const device = await searchEq();
				//获取到已绑定的设备集合
				this.devices = device.data.items;
				for (let item of this.devices) {
					let deviceObject = {
						id: item.id,
						appearance: item.appearance,
						sensor: item.sensor,
						gas: item.gas,
						mac: item.equipmentMac,
						status: this.equipmentSatus.offline,
						timestamp: 0, //时间戳用于计算设备是否离线
						deviceName: item.name,
						mqttValue: ["0", "0"], //给一个默认的值
						light: [5, 1],
						timestamp: new Date().getTime()
					}
					this.equipmentList.push(deviceObject);

					//将设备存储到设备map集合中
					this.devicesGroup();

					//调用近期使用设备方法
					if (this.vuex_initial_loading) {
						uni.showLoading({
							title: '跳转中...',
							mask: true
						})
						setTimeout(() => {
							uni.hideLoading();
							//1判断小程序是否是第一次加载 
							this.$u.vuex('vuex_initial_loading', false);
							this.recentUse();
						}, 2500)
					}

				}
			},

			//将设备存储到设备map集合中
			devicesGroup() {
				for (let item of this.devices) {
					this.bindDevice.set(item.equipmentMac, item.name)
				}
			},

			//根据蓝牙提供的设备外观和传感器从数据库查询出对应的设备
			async searchNewEquipment(equipmentObjInfo) {
				//生成查询数据
				let queryData = {
					sensorId: equipmentObjInfo.sensor,
					appearanceId: equipmentObjInfo.appearance
				}
				const resp = await searchEqByQuery(queryData);
				//生成对象来存储设备信息
				let data = resp.data;
				let deviceObject = {
					appearance: data.appearance,
					sensor: data.sensor,
					gas: data.gas,
					mac: equipmentObjInfo.mac,
					status: this.equipmentSatus.newEquipment,
					deviceId: equipmentObjInfo.deviceId,
					mqttValue: ["0", "0"], //给一个默认的值
					timestamp: new Date().getTime()
				}
				//添加到设备数组中去,在前端渲染出来
				this.equipmentList.unshift(deviceObject);
				this.sortDeviceList();
			},

			//连接mqtt 函数
			connectMqtt() {
				var that = this;
				const options = {
					connectTimeout: 10000, // 超时时间
					clientId: 'wx_' + parseInt(Math.random() * 10000 + 8000, 10),
				}

				this.client = mqtt.connect(host, options)
				this.client.on('reconnect', (error) => {
					// this.connectMqtt();
					console.log('正在重连:', error)
				})

				this.client.on('error', (error) => {
					console.log('连接失败:', error)
				})

				this.client.on('connect', (e) => {
					//存储一份mqtt连接成功变量
					that.$u.vuex('vuex_mqtt_is_connection_success', true)
					//mqtt 的连接客户端储存一份到vuex
					that.$u.vuex('vuex_mqtt', that.client)
					//订阅一个主题
					this.client.subscribe('methanal', {
						qos: 2
					}, function(err) {
						if (!err) {
							console.log("订阅成功")
						}
					})
				})
				this.client.on('message', function(topic, message) {

					//接收到设备发送的数据
					var data = JSON.parse(message)

					if (data.MAC.indexOf("clear_ok") > -1) {
						//2 解除设备绑定
					} else {
						//接收到设备的消息
						// console.log("mqtt----->",data);
						that.receivingDeviceMessage(data);
						//判断是否已经选择了设备如果有 直接跳转到首页

					}

				})
			},

			//接收到mqtt的数据进行一些列的处理
			receivingDeviceMessage(data) {
				// console.log("---->",data);
				//判断是那个设备发送的mqqt消息给我,并将这个设备显示为在线
				for (var i = 0; i < this.equipmentList.length; i++) {
					//通过双方mac地址进行比较
					if (this.equipmentList[i].mac == data.MAC) {
						//更新设备状态
						let newEquipment = this.equipmentList[i].status = this.equipmentSatus.online;
						// 对原有的字段进行重新赋值
						this.equipmentList[i].status = newEquipment;
						this.equipmentList[i].timestamp = Date.now();
						//调用排序方法
						this.sortDeviceList();
						break;
					}
				}

				//判断当前选择的是那个设备
				let selectEquipmen = this.vuex_select_equipment;
				if (data.MAC == this.vuex_select_mac) {
					// console.log("设备---->",selectEquipmen);
					// console.log("-------->",data.MAC,this.vuex_select_mac);
					this.$set(selectEquipmen, 'mqttValue', data.Value.split(":"));
					this.$set(selectEquipmen, 'light', data.light.split("-"));
					this.$set(selectEquipmen, 'status',this.equipmentSatus.online);
					this.$set(selectEquipmen, 'timestamp', new Date().getTime());
					this.$u.vuex('vuex_select_equipment',selectEquipmen)

					//新连接设备也赋值

					let newEquipment = this.vuex_new_equipment;
					this.$set(newEquipment, 'light', data.light.split("-"));
					this.$set(newEquipment, 'status', this.equipmentSatus.online);
					this.$set(newEquipment, 'timestamp', new Date().getTime());
					//名字修改 问题 2 mqtt 亮度问题  自动 切换手动不对
					this.$set(newEquipment, 'deviceName', selectEquipmen.deviceName);
				}
			},

			//蓝牙相关
			initBluetooth() {
				uni.openBluetoothAdapter({
					success: res => {
						this.findBluetooth();
					},
					fail: res => {
						console.log(res)
						this.showModal = true;
						if (res.errCode === 10001) {
							this.showModal = true;
						}
					}
				});
			},

			//寻找蓝牙
			findBluetooth() {
				uni.startBluetoothDevicesDiscovery({
					allowDuplicatesKey: true,
					success: res => {
						this.bluetoothEquipment();
					}
				});

			},

			//搜索寻找蓝牙
			//搜索到蓝牙设备
			// 只进行搜索一次
			bluetoothEquipment() {
				let _this = this;
				uni.onBluetoothDeviceFound(res => {
					res.devices.forEach(device => {
						//搜索以equipmentPrefix 前缀开头的设备
						// console.log("---->",device);
						if (device.localName) {
							if (device.localName.indexOf(_this.equipmentPrefix) !== -1) {
								//通过蓝牙名称提取出 设备外观和传感器类型  案例名称:JQ1_A9_S5_ECDA3B206B6E
								//JQ1 前缀  A9 设备外观 S5 传感器类型  ECDA3B206B6E 蓝牙mac
								let equipmentData = device.localName.split("_");
								//设备外观
								let appearance = equipmentData[1].replace("A", "");
								//传感器类型
								let sensor = equipmentData[2].replace("S", "");
								//设备mac地址
								let mac = equipmentData[3];

								//蓝牙deviceId地址
								let deviceId = device.deviceId;

								//判断map集合中是否已经添加了该设备
								if (!_this.equipmentMap.has(mac)) {
									//生成设备对象信息
									let equipmentObjInfo = {
										sensor: parseInt(sensor),
										appearance: parseInt(appearance),
										mac,
										deviceId
									}

									//排除

									//key mac地址  value 时间戳
									_this.equipmentMap.set(mac, Date.now())
									//将收集好的参数传递给searchNewEquipment(param)方法让其去查询设备的外观和设备的传感器类型
									_this.searchNewEquipment(equipmentObjInfo);
								} else {
									//如果设备已已经存在 则更新map里面的时间戳就好
									_this.equipmentMap.set(mac, Date.now())
								}
							}
						}

					});
				});
			}
		}
	}
</script>

<style lang="scss" scoped>
	.online {
		color: #BC9C5E;
	}

	.no_equipment {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		margin-top: 300rpx;
	}

	.equipment {
		padding: 0 0.9rem;
		display: flex;
		flex-wrap: wrap;
		flex-direction: row;
		justify-content: space-between;

		.item {
			position: relative;
			width: 330rpx;
			height: 350rpx;
			margin-top: 30rpx;

			.backdrop {
				position: absolute;
			}

			.equipment {
				position: absolute;
				top: -30rpx;
				left: -30rpx;
			}

			.text {
				position: absolute;
				bottom: 120rpx;
				font-size: 27rpx;
				left: 13rpx;
			}

			.status {
				position: absolute;
				bottom: 80rpx;
				left: 80rpx;
				font-size: 20rpx;
				display: flex;
				justify-content: center;
				width: 100%;
			}
		}
	}
</style>